<?php
/*
# ------------------------------------------------------------------------
# JA Job Board Package
# ------------------------------------------------------------------------
# Copyright (C) 2004-2010 JoomlArt.com. All Rights Reserved.
# @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
# Author: JoomlArt.com
# Websites: http://www.joomlart.com - http://www.joomlancers.com.
# ------------------------------------------------------------------------
*/

/**
 * @package		Joomla
 * @subpackage	JobBoard
 */
defined('_JEXEC') or die('Restricted access'); 
error_reporting(E_ALL ^ E_NOTICE);

global $jbconfig;

/*
	Import Data Proccess
*/

class xmlFeedImporter extends JObject {
	// Variables
	var $parser;
	var $feed_id;
	var $char_data = array();
	var $data = array();
	var $keyStack = array();
	var $line;
	var $depth;
	var $fp;
	var $feed_row;
	var $strImportError; 
	var $verbose;
	var $db;
	var $imported;

    // function with the default parameter value
    function xmlFeedImporter($feedID) {
    	$this->db =& JFactory::getDBO();
        $this->feed_id = $feedID;
		$this->line = 0;
		$this->depth = 0;
		$this->imported = 0;
		$this->feed_row = JAJobBoardModelJAXMLImport::fcnLoadFeedRow($feedID);
		switch($this->feed_row['Method']) {
			case 'FILE':
				if (file_exists($this->feed_row['FeedFileName'])) {
					$this->fp = fopen($this->feed_row['FeedFileName'], 'r');
				} else {
					$this->fcnSetImportDataError("File not found ".$this->feed_row['FeedFileName']);
					return false;
				}
				break;
			case 'URL':
				$url = $this->feed_row['FeedURL'];
				$str = $this->fcnGetData($url);				
				jimport('joomla.filesystem.file');
				JFile::write( JPATH_SITE.DS."cache".DS."temp.xml", $str);
				
				$this->fp = fopen(JPATH_SITE.DS."cache".DS."temp.xml", 'r'); //$this->fcnGetData($url);
								
				if (!$this->fp) {
					$this->fcnSetImportDataError('Cannot open URL '.$this->feed_row['FeedURL']);
					return false;
				}
						
				break;
			case 'FTP':
					$ftp_server = trim($this->feed_row['FTPHost']);
					$ftp_user = trim($this->feed_row['FTPUser']);
					$ftp_pass = trim($this->feed_row['FTPPass']);
					$remoteFile = trim($this->feed_row['FTPFileName']);
					// Connect to server
					if (!$connID = ftp_connect($ftp_server)) {
						$this->fcnSetImportDataError("FTP: Couldn't connect to $ftp_server"); 
						return false;
					}
					// Login via FTP
					if (ftp_login($connID, $ftp_user, $ftp_pass)) {
					
						// Active passive mode to connect
						$passive = ftp_pasv($connID, true);
						
						// Create xml_export directory in: site/components/com_jajobboard/uploads/
						jimport('joomla.filesystem.folder');
						
						global $jbconfig;
						
						$dir = JPATH_SITE.$jbconfig['general']->get('upload_folder',DS.'images'.DS.'stories'.DS.'jbuploads');
						
						if(!JFolder::exists($dir)){
							JFolder::create($dir);
						}
						$s = md5(time());
						$tmpFileName = $dir.DS.'import_temp_'.$s.'.xml';
						
					    if ($fpTemp = fopen($tmpFileName, 'w')) {
							if (ftp_fget($connID, $fpTemp, $remoteFile, FTP_BINARY, 0)) {
								FCLOSE($fpTemp);
								$this->fp = fopen($tmpFileName, 'r');
							} else {
								$this->fcnSetImportDataError("FTP: Couldn't download $remoteFile\n");
								return false;
							}
						}
						ftp_close($connID);
					} else {
						$this->fcnSetImportDataError("FTP: Couldn't login as $ftp_user\n");
						return false;
					}
					// close the connection
					@ftp_close($connID);
				break;
		}
		
		$this->FMD = &$this->feed_row['FMD'];
    }
	
    // parse XML data
    function import()  {
		global $mainframe;
		$my = $mainframe->getUser();
		$this->fcnCreateLogEntry("\n------------------------------------------------------------------------------------");
		$this->fcnCreateLogEntry("Imported Logs on ".date("M d, Y H:i")." by ".$my->username.": ");
		
		if (!$this->fp) {
			echo "File pointer failed: Cannot open URL \n";
			return false;
		}
        
        $this->parser = xml_parser_create ("UTF-8");
        xml_set_object($this->parser, $this);
        xml_set_element_handler($this->parser, 'beginXML', 'endXML');
        xml_set_character_data_handler($this->parser, 'charXML');
        xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false);
        
		while (($data = fgets($this->fp))) {
		    
		    $data = str_replace("&", "AND_CHAR", $data);
		    			
			if (strpos($data, '<?xml')===false) {
				if (!xml_parse($this->parser, $data, feof($this->fp))) {
					$this->error(sprintf('XML error at line %d column %d',
					xml_get_current_line_number($this->parser),
					xml_get_current_column_number($this->parser)));
					fclose ($this->fp);
					return false;
				}
			}
		}
		fclose ($this->fp);
		return $this->imported;
    }
	
    function fcnGetData( $url ){
        
        $req = '';
   
    	if (! function_exists ( 'curl_version' )) {
    		if (! ini_get ( 'allow_url_fopen' )) {
    			JError::raiseWarning ( 1, JText::_ ( 'Sorry, but your server does not currently support open method. Please contact the network administrator system for help.' ) );
    			return;
    		} else {
    			$result = socket_getdata ($url, "", $req );
    		}
    	} else {
    		$result = curl_getdata ( $url, $req );
    	}
    	
    	if( $result )
    	   return $result;
    	else return false;
    }
    
    function beginXML($parser, $name, $attr)    {
		$this->depth++;
		$this->key_stack[] = $name;
		$key = implode('|', $this->key_stack);
		$this->data[$key]['attr'][] = $attr;
        
    }
	
    function endXML($parser, $name)    {
		$key = implode('|', $this->key_stack);
		if (is_array($this->char_data[$key])) {
			$data = implode('',$this->char_data[$key]);
		}
		$this->char_data[$key]=array();
		$data = str_replace(array("<", ">"), array("AND_CHARlt;", "AND_CHARgt;"), $data);
		$this->data[$key]['data'] = $data;		
		if ($key == $this->FMD->seq) {
			fcnDoCallBack('xml_import_fcnProccessData', $this);
			$this->fcnProccessData();
		}
		array_pop($this->key_stack);
		$this->depth--;
    }

	function fcnConvertUTFtoHTML ($data) {
	    return preg_replace("/([\\xC0-\\xF7]{1,1}[\\x80-\\xBF]+)/e", 'fcnUTF8toHTMLData("\\1")', $data);
	}
	
	function fcnUTF8toHTMLData ($data) {
	    $ret = 0;
	    foreach ((str_split(strrev(chr((ord($data{0}) % 252 % 248 % 240 % 224 % 192) + 128) . substr($data, 1)))) as $k => $v)
	        $ret += (ord($v) % 128) * pow(64, $k);
		if ($ret<256) return chr($ret); // no need to convert to entities
	    return "&#$ret;";
	}
    
    function charXML($parser, $data)    {
		$key = implode('|',$this->key_stack);
		$this->char_data[$key][] = $data;			
    }

    function error($msg)    {
        if ($this->verbose) {
			echo "<div align=\"center\">
            <font color=\"red\"><b>Error: $msg</b></font>
            </div>";
		}
		$this->fcnSetImportDataError("XML Parse error: $msg");
        return false;
    }

	function fcnSetDataValue($value, $strFieldID, $strFormID=1) {
		if ($strFormID==1) {
			$map = &$this->FMD->getOption('job_map');
		} elseif ($strFormID==4) {
			$map = &$this->FMD->getOption('account_map');
		}
		$this->data[$map[$strFieldID]['element']]['data'] = $value;
	}

	function fcnGetRawDataValue($strFieldID, $strFormID=1) {
		if ($strFormID==1) {
			$map = &$this->FMD->getOption('job_map'); // job post mappings
		} elseif ($strFormID==4) {
			$map = &$this->FMD->getOption('account_map'); // employer's account mappings
		}
		if(isset($this->data[$map[$strFieldID]['element']]['data']))
			$val = $this->data[$map[$strFieldID]['element']]['data'];
		else
			$val = "";
		return $val;
	}


	function fcnGetDataValue($strFieldID, $strFormID=1) {
		$val = "";		
		if ($strFormID==1) {
			// Job info
			$map = &$this->FMD->getOption('job_map');
		} elseif ($strFormID==4) {
			// Account info
			$map = &$this->FMD->getOption('account_map');
		}
		
		if ($map[$strFieldID]['ignore']=='Y' || ($map[$strFieldID]['cat_mode'] == 'ADD_DEFAULT'&& $map[$strFieldID]['parent_category_default'] != '')) { 
			$val  = ($map[$strFieldID]['replace'] != "")?$map[$strFieldID]['replace']:$map[$strFieldID]['parent_category_default'];
			return $val;
		} else {
			$val = $this->data[$map[$strFieldID]['element']]['data'];
		}
		
		$val = $this->fcnCleanUpData($val);
		if ($map[$strFieldID]['allow_html']!='Y') {
			$val = strip_tags($val);
		}
		return  str_replace( array("&#8212;", "&#8226;", "&#39;"),array(" - ", " - ", "'"),html_entity_decode($val));
	}

	function fcnGetDataValues($strFieldID, $strFormID=1) {
		$val = "";		
		if ($strFormID==1) {
			// Job info
			$map = &$this->FMD->getOption('job_map');
		} elseif ($strFormID==4) {
			// Account info
			$map = &$this->FMD->getOption('account_map');
		}
		
		if ($map[$strFieldID]['ignore']=='Y' || ($map[$strFieldID]['cat_mode'] == 'ADD_DEFAULT'&& $map[$strFieldID]['parent_category_default'] != '')) { 
			$val  = ($map[$strFieldID]['replace'] != "")?$map[$strFieldID]['replace']:$map[$strFieldID]['parent_category_default'];
			return $val;
		} 
		return false;
	}
	
	function fcnCleanUpData($data) {		
		$data = trim($data);
		if (strpos($data, '<![CDATA[')===0) {
			$data = str_replace(array('<![CDATA[', ']]>'), array('', ''), $data);
		} else {
			$trans = array(
			'&lt;' => "<", 
			 '&amp;'=> "&", 
			 '&gt;'=> ">", 
			 '&quot;'=> '"',  
			 '&apos;'=> '\'');

			$data = strtr($data, $trans);
		}
		
		$data = $this->fcnConvertUTFtoHTML ($data);
		$data = fcnRemoveEvilTag($data);		
		
		return $data;
	}
	
	function fcnProccessData() {
		$this->fcnInsertNewData();
		fcnDoCallBack('xml_import_insert_response', $this);
		$this->data = array();
		$this->strImportError='';
	}

	function fcnInsertNewData() {
		$arrJobMap = &$this->FMD->getOption('job_map'); 
		$account_map = &$this->FMD->getOption('account_map');
		
		if ( $this->fcnDataValidator() !== false) {
			$strEmployerID = $this->fcnEmployerProccessor();
			if ($strEmployerID === false) {
				$this->fcnSetImportDataError('Error: Could not determine the employer_id');
			} else {				
				$this->fcnInsertNewJob($strEmployerID);
			}
		}
	}
	
	// Validate data from Source data
	function fcnDataValidator() {	
		$arrJobMap = &$this->FMD->getOption('job_map');
		$account_map = &$this->FMD->getOption('account_map'); 
		foreach ($arrJobMap as $strFieldID=>$field_map) {
			$data = $this->fcnGetRawDataValue($strFieldID);
			switch ($field_map['validate']) {
				case 'not_blank':
					if ($data =='') {
						$this->fcnSetImportDataError ("Invalid data: <".$field_map['element']."> is blank");
						return false;
					}
					break;
				case 'alphanumeric':
					if (!preg_match('#^[a-z0-9Ã€-Ã¿\-_\.@]+$#Di', $data)) {
						$this->fcnSetImportDataError ("Invalid data: <".$field_map['element']."> is not alphanumeric");
					}
					return false;
					break;
				case 'email':
					if (!$this->fcnEmailValidator($data)) {
						$this->fcnSetImportDataError ("Invalid data: <".$field_map['element']."> is not email");
						return false;
					}
					break;
				case 'numeric':
				case 'currency':
					preg_match('/[\+-]?([0-9,]+(\.)?(\d+)?)/', $data, $m);
					$m[1] = str_replace(',', '', $m[1]); 
					if (!$m[1]==='') {
						$this->fcnSetImportDataError ("Invalid data: <".$field_map['element']."> is not numeric");
						return false;
					} 
					break;
				case 'url':
					if (!preg_match ( '/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i', $data)) {
						$this->fcnSetImportDataError ("Invalid data: ".$field_map['element']." is not URL");
						return false;
					}
					break;
			}
		}
		return true;
	}
	
	// Validate e-mail address
	function fcnEmailValidator($Email) {
	 	global $HTTP_HOST;
	 	$result = array();
	 	$Pattern = "/^([_a-z0-9-]+)(\.[_a-z0-9-]+)*@([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,})$/siD";
	 	if (!preg_match($Pattern, $Email)) {
	 		return false;
	 	}
	 	return true;
	}
	
	function fcnGetSQLInsertFields($strFormID=1) {
		$tagFieldID = $this->fcnGetTAGtoFieldID($strFormID);
		foreach ($tagFieldID as $tag=>$field) {
			if ( ($field['field_type'] == 'BLANK') || ($field['field_type'] =='SEPERATOR') || ($field['field_type'] =='NOTE')) {
				continue;
			}
			$str .= ", `".$field['field_label']."` ";
		}
		return $str;
	}
	
	function fcnGetTAGtoFieldID($strFormID=1){
		if($strFormID == 1){
			$arrField = getEditFieldList("ja_jobs", " AND f.field_name <> 'user_id' ");
			foreach ($arrField as $k=>$v){
				$tagFieldID[$v->field_name]["field_id"] = $v->id;
				if($v->field_type == 'SELECT' || $v->field_type == 'MSELECT')
					$tagFieldID[$v->field_name]["field_type"] = "CATEGORY";
				elseif($v->field_type == 'DATE_CAL')
					$tagFieldID[$v->field_name]["field_type"] = "DATE_CAL";
				else
					$tagFieldID[$v->field_name]["field_type"] = "TEXT";
				$tagFieldID[$v->field_name]["field_label"] = $v->field_name;
			}			
		}else{
			$tagFieldID["name"]["field_id"] = "FirstName";
			$tagFieldID["name"]["field_label"] = "name";
			$tagFieldID["name"]["field_type"] = "TEXT";
			
			$tagFieldID["username"]["field_id"] = "Username";
			$tagFieldID["username"]["field_label"] = "username";
			$tagFieldID["username"]["field_type"] = "TEXT";
			
			$tagFieldID["email"]["field_id"] = "Email";
			$tagFieldID["email"]["field_label"] = "email";
			$tagFieldID["email"]["field_type"] = "TEXT";
		}
		return $tagFieldID;
	}
	
	function fcnGetSQLInsertValues($strFormID=1) {
		$tagFieldID = $this->fcnGetTAGtoFieldID($strFormID);
		foreach ($tagFieldID as $tag=>$field) {
			
			if ( ($field['field_type'] == 'BLANK') || ($field['field_type'] =='SEPERATOR') || ($field['field_type'] =='NOTE')) {
				continue;
			}
			$strFieldID = $field['field_id'];
			$data = $this->fcnGetDataValue($strFieldID, $strFormID);
			$default = $this->fcnGetDataValues($strFieldID, $strFormID);

			switch ($field['field_type']) {

				case 'CATEGORY':
					$strCatID = $this->fcnCategoryProccessor($field['field_label'], $strFieldID, $data, $strFormID);
					if ($strCatID === false) {
						$this->fcnSetImportDataError('Skipping record because the system failed to match the category for '.$field['field_label'].' - :['.$data.'] was not on your system. Form_id:'.$strFormID);
						return false;
					}
					if($default) $strCatID = $default;
					$str .= ", '".fcnEscapeSQLCommand($strCatID)."' ";
					break;
				case 'MSELECT':
				case 'CHECK':
					$options = explode(',',$data); 
					$codes =''; $comma='';
					foreach ($options as $option) {
						if (($code = $this->fcnOptionProccessor($strFieldID, $option))===false) {
							return false;
						}
						if ($code!='') {
							$codes .= $comma.fcnEscapeSQLCommand($code);
							$comma = ',';
						}
					}
					$str .= ", '".$codes."' ";

					break;
				case 'SELECT':
				case 'RADIO':
					if (($code = $this->fcnOptionProccessor($strFieldID, $data))===false) {
						return false;
					}
					$str .= ", '".fcnEscapeSQLCommand($code)."' ";
					break;
				case 'DATE_CAL':
					$str .= ", '".fcnEscapeSQLCommand(date("Y-m-d", strtotime($data)))."' ";
					break;
				default:
					$str .= ", '".fcnEscapeSQLCommand($data)."' ";
					break;
			}
		}
		return $str;
	}	
	
	function fcnAddNewCode($strFieldID, $descript, $code='') {
		if (trim($descript)=='') return false;
		if ($code=='') {
			$str = $descript; 
			$i=0;
			preg_match('/^[a-z0-9]{3}/iD', $str, $m[0]);
			$code = strtoupper($m[0][0]);
			$sql = "SELECT * from codes where field_id='".fcnEscapeSQLCommand($strFieldID)."' AND code like '%".fcnEscapeSQLCommand($code)."%' LIMIT 1 ";
			$result = fcnMySQLQueryProccess ($sql) or die (mysql_error());
			while (mysql_num_rows($result)==true) {
				$i++;
				if ($i>3) {
					return false;
				}
				$str = $str.chr(rand(ord('A'),ord('Z')));
				$sql = "SELECT * from codes where field_id='".fcnEscapeSQLCommand($strFieldID)."' AND code like '%".fcnEscapeSQLCommand($code)."%' ";
				$result = fcnMySQLQueryProccess ($sql) or die (mysql_error());
				preg_match('/^[a-z0-9]{3}/iD', $str, $m[0]);
				$code = strtoupper($m[0][0]);
				$count = mysql_num_rows($result);
			}
		}
		fcnInsertNewCode($strFieldID, $code, $descript);
		return $code;
	}
	
	function fcnAddNewCategory ( $catName, $parent, $table, $fieldLabel) {
		if($table != "#__")
	   		$query = "INSERT INTO $table (name, parent_id) VALUES ('$catName', '$parent')";
	   	else {
	   		$value = rand(10,100);
	   		$query = "INSERT INTO #__ja_codes (field_id, value, text) VALUES ('ja_jobs_{$fieldLabel}', '{$value}', '$catName')";
	   	}
	   
	   $this->db->setQuery($query);
	   $this->db->query();
	   
	   if($table != "#__ja_codes"){
	   		$this->db->setQuery("SELECT LAST_INSERT_ID()");
	   		$id =  $this->db->loadResult();
	   }else {
	   		$id = $value;
	   }
	   return $id;
	}

	function fcnAddCategory($parentID, $name, $strFormID=1, $table = "#__ja_location", $fieldLabel) {
		$strCatID = $this->fcnAddNewCategory ( $name, $parentID, $table, $fieldLabel);
		return $strCatID;
	}
	
	function fcnGetSQLUpdateValues($strFormID=1) {
		$tagFieldID = fcnGetTAGtoFieldID($strFormID);
		foreach ($tagFieldID as $tag=>$field) {
			if (!is_numeric($field['field_id']) || ($field['field_type'] == 'BLANK') || ($field['field_type'] =='SEPERATOR') || ($field['field_type'] =='NOTE')) {
				continue;
			}
			
			$strFieldID = $field['field_id'];
			$data = $this->fcnGetDataValue($strFieldID, $strFormID);

			switch ($field['field_type']) {

				case 'CATEGORY':
					$strCatID=$this->fcnCategoryProccessor($strFieldID, $data, $strFormID);

					if ($strCatID === false) {
						$this->fcnSetImportDataError('Skipping record because the system failed to match the category. Guid:  '.$guid);
						return false;
					}
					$str .= ", `".$strFieldID."`='".fcnEscapeSQLCommand($strCatID)."' ";

					break;
				// coded fields
				case 'MSELECT':
				case 'CHECK':
					
					$options = explode(',',$data); 
					$codes =''; $comma='';
					foreach ($options as $option) {
						if (($code = $this->fcnOptionProccessor($strFieldID, $option))===false) {
							return false;
						}
						if ($code!='') {
							$codes .= $comma.fcnEscapeSQLCommand($code);
							$comma = ',';
						}
					}
					$str .= ", `".$strFieldID."`='".$codes."' ";
					break;
				case 'SELECT':
				case 'RADIO':
					if (($code = $this->fcnOptionProccessor($strFieldID, $data))===false) {
						return false;
					}
					$str .= ", `".$strFieldID."`='".fcnEscapeSQLCommand($code)."' ";
					break;
				default:
					$str .= ", `".$strFieldID."`='".fcnEscapeSQLCommand($data)."' ";
					break;
			}
		}
		return $str;
	}

	function fcnEmployerProccessor() {
		$strAccCreate = $this->FMD->getOption('account_create');
		$pass_md5 = $this->FMD->getOption('pass_md5');
		$username = $this->fcnGetDataValue('Username', 4);
		$password = $this->FMD->getOption('ac_Password');
		
		if (($strAccCreate!='IMPORT_CREATE') && ($strAccCreate!='ONLY_DEFAULT')) {
			if (trim($password)=='') {
				$password = md5($password);
			}
		}
		
		switch ($strAccCreate) {
			case 'IMPORT_REJECT':
				if ($strEmployerID = $this->fcnGetEmployerID($username, $password)) {
					return $strEmployerID;
				} else {
					$this->fcnSetImportDataError("Invalid username/password ($username)/n");
					return false;
				}
				break;
			case 'IMPORT_DEFAULT':
				if ($strEmployerID = $this->fcnGetEmployerID($username, $password)) {
					return $strEmployerID;
				} elseif ($strEmployerID = $this->fcnGetEmployerID($this->FMD->getOption('default_user'))) {
					return $strEmployerID;
				} else {
					$this->fcnSetImportDataError("Invalid default username (".$this->FMD->getOption('default_user').") - Please verify default username when mapping trains/n");
					return false;
				}
				break;
			case 'IMPORT_CREATE':
				if ($strEmployerID = $this->fcnGetEmployerID($username, $password)) {
					return $strEmployerID;
				} else {
					$strEmployerID = $this->fcnInsertEmployerData();
					if ($strEmployerID===false) {
						$this->fcnSetImportDataError ("Employer account creation failed. There's probably insufficient information in the feed to create a new account/n");
						return false;
					}
					return $strEmployerID;
				}
				break;
			case 'ONLY_DEFAULT':
				if ($strEmployerID = $this->fcnGetEmployerID($this->FMD->getOption('default_user'))) {
					return $strEmployerID;
				} else {
					$this->fcnSetImportDataError ("Invalid default username (".$this->FMD->getOption('default_user').") - Please verify default username on the 'Map Fields' page./n");
					return false;
				}
				break;
			default:
				$this->fcnSetImportDataError("Account create option not set, see 'Map Fields' page./n");
				return false;
				break;
		}
	}

	function fcnGetCategoyIDFromName($name, $strFormID=1, $table = "#__ja_location", $key, $value) {
		if($table != "#__")
			$sql = "SELECT value FROM #__ja_codes WHERE text like '%".fcnEscapeSQLCommand($name)."%' ";
		else 
			$sql = "SELECT {$key} FROM {$table} WHERE {$value} like '%".fcnEscapeSQLCommand($name)."%' ";
		$this->db->setQuery($sql);
		$id = $this->db->loadResult();
		
		if($id)
			return $id;
		else
			return false;
	}	
	
	function fcnMatchTextCategory($text, $strFormID, $table = "#__ja_location", $key, $value) {
		
		$MAX_SEARCH = 5;
		$i=0;
		
		if (strlen($text)==0) return false;
		
		$words = preg_split ("/\s+/", $text);
		$result = array_count_values(array_map('strtolower', $words));
		arsort($result);
		while (($word=key($result)) && ($i < $MAX_SEARCH)) {
			$i++;
			if (strlen($word)<3) { 
				continue;
			}
			if ($strCatName = $this->fcnGetCategoyIDFromName($word, $strFormID, $table = "#__ja_location", $key, $value)) {
				return $strCatName;
			}
			next($result);	
		}
		return false;	
	}
	
	function fcnCategoryProccessor($fieldLabel, $strFieldID, $strCatName, $strFormID) {
		$db =& JFactory::getDBO();
		$strCatName = trim($strCatName);
		if ($strCatName=='') return $strCatName;
		$arrJobMap = &$this->FMD->getOption('job_map');
		$query = "SELECT * FROM #__ja_form_fields WHERE id = '{$strFieldID}'";
		$db->setQuery($query);
		$result = $db->loadAssoc();
		$table 	= "#__".$result['referred_table'];
		$key 	= $result['referred_key'];
		$value 	= $result['referred_value'];
		
		$strCatID = $this->fcnGetCategoyIDFromName($strCatName, $strFormID, $table, $key, $value);

		if (!$strCatID) {
			$strCatID=0; 
			switch ($arrJobMap[$strFieldID]['cat_mode']) {
				case 'ADD_NEW': 
					$strCatID = $this->fcnAddCategory($arrJobMap[$strFieldID]['parent_category'], $strCatName, $strFormID, $table, $fieldLabel);
					break;
				case 'ADD_DEFAULT': 
					$strCatID = $arrJobMap[$strFieldID]['parent_category_default'];
					break;
				case 'ADD_MATCH':
					$cat_match = $arrJobMap[$strFieldID]['cat_match'];
					$strCatID = $this->fcnMatchTextCategory($this->fcnCleanUpData($this->data[$cat_match]['data']), $strFormID, $table, $key, $value);
					if ($strCatID===false) {
						$this->fcnSetImportDataError("Error. Cannot match category for: [".$strCatName."] field_id: [$strFieldID] ");
					}
					break;
				case 'ERROR':
					$this->fcnSetImportDataError ("Error. No code exists for  '".$strCatName."' in the database, when importing <".$arrJobMap[$strFieldID]['element']."> ");
					return false;
					break;
				case 'IGNORE':
					break;
			}
		}
		return $strCatID;
	}

	function fcnOptionProccessor ($strFieldID, $option) {
		$option = trim($option);
		if ($option=='') return $option; 
		if (JB_is_valid_code($strFieldID, $code)) {
			return $code;
		} else {
			$code = fcnGetCodeFromDescription ($strFieldID, $option);
			if ($code) return $code;
		}
		$arrJobMap = &$this->FMD->getOption('job_map');
		$code = 0;
		switch ($arrJobMap[$strFieldID]['code_mode']) {
			case 'ADD_NEW':
			echo "field_id, option [$strFieldID], [$option]";
				$code = $this->fcnAddNewCode($strFieldID, $option);
				if ($code===false) {
					$this->fcnSetImportDataError("Error. Cannot add new code - invalid option $option for field $strFieldID");
				}
				break;
			case 'ADD_PAIR':
				$code = $this->fcnCleanUpData($this->data[$arrJobMap[$strFieldID]['code_pair']]['data']);
				if ($code=='') {
					$code = false;
					$this->fcnSetImportDataError ("Error. Could not get the option's code for the option '".$option."', when importing <".$arrJobMap[$strFieldID]['element']."> - (looking in ".$arrJobMap[$strFieldID]['code_pair'].", this can be set Admin->XML Import, Map Fields) ");
				} else {
					$this->fcnAddNewCode($strFieldID, $option, $code);
				}
				break;
			case 'ERROR': 
				$this->fcnSetImportDataError ( "Error. No code exists for option '".$option."' in the database, when importing <".$arrJobMap[$strFieldID]['element']."> (This can be set Admin->XML Import, Map Fields)");
				break;
			case 'IGNORE': 
				$code = true;
				break;
			default:
				break;
		}
		return $code;
	}

	function fcnInsertEmployerData() {
		if (!$this->fcnValidateEmployer()) {
			return false;
		}
		
		$username = $this->fcnGetDataValue('Username', 4);
		$password = $this->FMD->getOption('account_map');
		$password = $password['Password']['element'];
		
		jimport('joomla.user.helper');
		$salt  = JUserHelper::genRandomPassword(32);
		$crypt = JUserHelper::getCryptedPassword($password, $salt);
		$password = $crypt.':'.$salt;
		
		$fname = $this->fcnGetDataValue('FirstName', 4);
		$email = $this->fcnGetDataValue('Email', 4);
		
		//$strEmployerID = JB_generate_employer_id ();
		$now = (gmdate("Y-m-d H:i:s"));
		
		// get the fiels part of the INSERT query
		$sqlFields = $this->fcnGetSQLInsertFields(4);
		if ($sqlFields===false) { 
			return false;
		}
		// get the values part of the INSERT query
		$sqlValues = $this->fcnGetSQLInsertValues(4);
		if ($sqlValues===false) {
			return false;
		}
		
		$db =& JFactory::getDBO();
		
		// Insert new user
		$sql = "INSERT INTO #__users  ( id, gid ".$sqlFields." , `password`, `params`, `registerDate`) VALUES ( NULL, '18' ".$sqlValues.", '".$password."', 'usertype=Guest', '".date("Y-m-d")."') ";
		$db->setQuery($sql);
		$db->query();
		$db->setQuery("SELECT LAST_INSERT_ID()");
		$strEmployerID = $db->loadResult();
		
		$sql = "INSERT INTO #__core_acl_aro  ( id, section_value, value, name) VALUES ( NULL, 'users', '".$strEmployerID."', '".$username."') ";
		$db->setQuery($sql);
		$db->query();
		$db->setQuery("SELECT LAST_INSERT_ID()");
		$last_id = $db->loadResult();
		
		$sql = "INSERT INTO #__core_acl_groups_aro_map  ( group_id, aro_id) VALUES ( '18', '".$last_id."') ";
		$db->setQuery($sql);
		$db->query();
		
		$this->fcnCreateLogEntry('Inserted Employer | '.$strEmployerID.' | '.$username.' | '.$email.' | '.$fname);
		return $strEmployerID;
	}
	
	function fcnValidateEmployer() {
		$username = $this->fcnGetDataValue('Username', 4);
		$fname = $this->fcnGetDataValue('FirstName', 4);
		$email = $this->fcnGetDataValue('Email', 4);		
		if (!preg_match('#^[a-z0-9Ã€-Ã¿\-_\.@]+$#Di', $username)) {
			$this->fcnSetImportDataError = ("Error: Cannot create a new employer account because if invalid username / username was blank [$username] ");
			return false;
		}
		if ($fname=='') {
			$this->fcnSetImportDataError ( "Error: Cannot create a new employer account because First Name was blank [$fname] ");
			return false;
		}
		if (!$this->fcnEmailValidator($email)) {
			$this->fcnSetImportDataError ( "Error: Cannot create a new employer account because email was invalid [$lname] ");
			return false;
		}
		return true;
	}
	
	function fcnGetEmployerID($username, $password=false) {
		$db =& JFactory::getDBO();
		$sql = "SELECT id FROM #__users WHERE username = '".$username."' ";
		$db->setQuery($sql);
		$result = $db->loadResult();
		return $result;
	}

	function fcnInsertNewJob($strEmployerID) {
		$db =& JFactory::getDBO();
		
		$sqlFields = $this->fcnGetSQLInsertFields(1);
		if ($sqlFields === false) { 
			return false;
		}
		
		$sqlValues = $this->fcnGetSQLInsertValues(1);
		if ($sqlValues===false) {
			return false;
		}
		
		$element = $this->FMD->getOption('job_identifier');
		$guid = $this->fcnCleanUpData($this->data[$element]['data']);
		
		$sql = "SELECT id FROM #__ja_jobs WHERE feed_guid = '".mysql_real_escape_string($guid)."' ";
		$db->setQuery($sql);
		
		$result = $db->query($sql);
		
		if ($result && $db->getNumRows($result)) {
			
			$sql_value = explode(",", $sqlValues);
			$sql_value = substr($sql_value[1], 0, 30)."...";
			$this->fcnCreateLogEntry(' - Job [ Title:'.$sql_value."'] [Inserted fail: Duplicate Job Identifier on database]");
			return array_pop(mysql_fetch_row($result));
		}
		
		$sqlValues = str_replace("AND_CHAR", "&", $sqlValues);	
		
		$id = JRequest::getVar("cid","0","", array());
		$id = $id[0];
		$sql = "INSERT INTO #__ja_jobs ( `feed_id`, `import_date`, `user_id`, `feed_guid` ".$sqlFields.") VALUES 
				( '{$id}', '".date("Y-m-d H:i:s")."', '".$strEmployerID."', '".mysql_real_escape_string($guid)."' ".$sqlValues.") ";
		
		$db->setQuery($sql);
		
		if ( $db->query() ){		
			$db->setQuery("SELECT LAST_INSERT_ID()");
			$post_id = $db->loadResult();

			//$db->setQuery("SELECT * FROM #__ja_jobs WHERE id = {$post_id}");
			//die(print_r($db->loadObjectList()));

			$sqlValues = explode(",", $sqlValues);
			$sqlValues = substr($sqlValues[1], 0, 30)."...";
			$this->imported++;
			$this->fcnCreateLogEntry(' - Job [ Title:'.$sqlValues.'\', ID:'.$post_id.', Emp.ID: '.$strEmployerID.", ] [Inserted successfuly]");
		}else{
			$this->fcnCreateLogEntry(' - Job [ Title:'.$sqlValues.'\' ] [Inserted fail]');
		}
		return $post_id;
	}

	
	function fcnShowImportError($str=false) {
		if ($this->verbose) {
			if ($str) {
				echo $str."\n";
			} else {
				echo $this->strImportError."<br>\n";
			}
		}
	}

	function fcnSetImportDataError($str, $level=1) {
		$this->strImportError=$str;
		$this->fcnShowImportError();
		$this->fcnCreateLogEntry($str);
	}

	function fcnCreateLogEntry($line) {
		$line = $date = $line."\n";		
		$s = md5(time());
				
		// Create xml_export directory in: site/components/com_jajobboard/uploads/
		jimport('joomla.filesystem.folder');
		jimport('joomla.filesystem.file');
		
		global $jbconfig;
		
		$dir = JPATH_SITE.$jbconfig['general']->get('upload_folder',DS.'images'.DS.'stories'.DS.'jbuploads');
		
		if(!JFolder::exists($dir)){
			JFolder::create($dir);
		}
		
		$file_name = $dir.DS.'import_log.txt';
		
		if (file_exists($file_name)) {
			if ((time()-filemtime($file_name)) > (time()+60*60)) { // older than 24 hrs?
				$open_mode = 'w'; // overwrite the file
				$line .= date("D, j M Y H:i:s O").' - '."Cleared the log\n".$line;
			} else {
				$open_mode = 'a';
			}
		} else {
			$open_mode = 'w';
		}
		$fp = fopen ($file_name, $open_mode);
		fputs($fp, $line);
		fclose($fp);
		
		if ($this->verbose) {
			echo $line;
			flush();
			ob_flush();
		}		
	}	
}


	class xmlFeedFieldParser {
		// Variables
		var $parser;	
		var $xml_strings;
		var $char_data = array();
		var $data = array();
		var $keyStack = array();
		var $line;
		var $depth;
		
		function xmlFeedFieldParser($strXML) {		
			$strXML = str_replace("&", "&amp;", $strXML);		
			$this->xml_strings = explode("\n", $strXML);
			$this->url  = "";
			$this->line = 0;
			$this->depth = 0;
			$this->parse();
		}  
		
		function parse(){
			$data = '';
			$this->parser = xml_parser_create ("UTF-8");
			xml_set_object($this->parser, $this);
			xml_set_element_handler($this->parser, 'beginXML', 'endXML');
			xml_set_character_data_handler($this->parser, 'charXML');
			xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false);		
			$lineCount = sizeof($this->xml_strings);
			$i=0;
			$lastLine=false;
			foreach ($this->xml_strings as $line) {
				if ($lineCount==$i) {
					$lastLine = true;
				}
				if (!xml_parse($this->parser, $line, $lastLine)) {
					$this->error(sprintf('XML error at line %d column %d',
					xml_get_current_line_number($this->parser),
					xml_get_current_column_number($this->parser)));
				}
				$i++;
			}
		}
		
		function beginXML($parser, $name, $attr){
			$this->depth++;
			$this->key_stack[] = $name;		
			$key = implode('|', $this->key_stack);
			$this->data[$key]['attr'][] = $attr;        
		}
	
		function endXML($parser, $name) {
			$key = implode('|', $this->key_stack);
			if (is_array($this->char_data[$key])) {
				$data = implode('',$this->char_data[$key]);
			}		
			$this->char_data[$key]=array();		
			$data = $data;
			$this->data[$key]['data'][] = $data;
			array_pop($this->key_stack);		
			$this->depth--;
		}
	
		function charXML($parser, $data){
			$data = trim($data);
			$key = implode('|',$this->key_stack);
			$this->char_data[$key][] = $data;			
		}
	
		function error($msg)    {
			echo "<div align=\"center\">
				<font color=\"red\"><b>Error: $msg</b></font>
				</div>";
			exit();
		}
	}
	
	// Call back functions if required	
	function fcnDoCallBack($strCallbackName, &$A) {
		global $glbPlugins;
		global $arrCallBacks;
		if (!isset($arrCallBacks[$strCallbackName])) return false;
		$hooks = $arrCallBacks[$strCallbackName];
		if ($A!==false) {
			$args .= $comma.'$A';
			$comma = ', ';
		}
		for ($i=2; $i < func_num_args(); $i++) {
			$argn = chr(65+$i);
			$$argn = func_get_arg($i);	
			$args .= $comma.'$'.$argn;
			$comma = ', ';
		}
		if (sizeof($hooks) > 0) {
			foreach ($hooks as $hook) {		
				if ($args!='') {
					$the_call = '$glbPlugins["'.$hook['call'][0].'"]->'.$hook["call"][1].'('.$args.');';
					eval ($the_call);
				} else {
					$glbPlugins[$hook['call'][0]]->$hook["call"][1]();
				}
			}
			return true;
		}
		return false;	
	}
	
	// To standard sql command
	function fcnEscapeSQLCommand($str) {			
			return mysql_real_escape_string($str);
		}
	
	// Scrub XSS string
	function fcnXSSScrub($str) {
		if (!is_string($str)) {
			return false;
		}
		if (preg_match_all('/&#(x)?0{0,8}([0-9a-f]+);?/i', $str, $m)) {
			foreach ($m[2] as $key=>$num) {
				if ($m[1][$key]!='') { 
					$num = hexdec($num);
				}
				if ($num < 0x7E) { 
					$str = str_replace($m[0][$key], chr($num), $str);
				}
			}
		}
		$str = preg_replace('/([\x00-\x08][\x0b-\x0c][\x0e-\x20])/', '', $str);
		return $str;
	}
	
	// Remove evil tag from source
	function fcnRemoveEvilTag($src) {
	   $src = fcnXSSScrub($src);
	   $allowedTags = '<h1><b><br><br><i><a><ul><li><hr><blockquote><img><span><div><font><p><em><strong><center><div><table><td><tr>';
	   $src = strip_tags($src, $allowedTags);
	   return fcnRemoveEvilAttributes($src);
	}
	
	// Remove evil attributes from tag source
	function fcnRemoveEvilAttributes($tagSource) {
		$stripAttrib = '/style[\s]+?=|class[\s]+?=|onabort|onactivate|onafterprint|onafterupdate|onbeforeactivate|onbeforecopy|onbeforecut|onbeforedeactivate|onbeforeeditfocus|onbeforepaste|onbeforeprint|onbeforeunload|onbeforeupdate|onblur|onbounce|oncellchange|onchange|onclick|oncontextmenu|oncontrolselect|oncopy|oncut|ondataavailable|ondatasetchanged|ondatasetcomplete|ondblclick|ondeactivate|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|onerror|onerrorupdate|onfilterchange|onfinish|onfocus|onfocusin|onfocusout|onhelp|onkeydown|onkeypress|onkeyup|onlayoutcomplete|onload|onlosecapture|onmousedown|onmouseenter|onmouseleave|onmousemove|onmouseout|onmouseover|onmouseup|onmousewheel|onmove|onmoveend|onmovestart|onpaste|onpropertychange|onreadystatechange|onreset|onresize|onresizeend|onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onselect|onselectionchange|onselectstart|onstart|onstop|onsubmit|onunload/i';
		$tagSource = preg_replace($stripAttrib, '  ', $tagSource);
		return $tagSource;
	}
	
	// Convert UTF-8 charactes to HTML string
	function fcnUTF8toHTMLData ($data) {
		return $data;	
		$ret = 0;	
		foreach ((str_split(strrev(chr((ord($data{0}) % 252 % 248 % 240 % 224 % 192) + 128) . substr($data, 1)))) as $k => $v)
			$ret += (ord($v) % 128) * pow(64, $k);
		if ($ret<256) return chr($ret);
		return "&#$ret;";
	}
?>